package io.jee.medusa.orm.condition;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;

import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

public class Condition<T> {
	
	private Session session;
	private StringBuffer hql;
	private Middle middle = new Middle();
	private Order order = new Order();
	private Result result = new Result();
	private Map<String, Object> param = new HashMap<>();
	private Map<String, String> orderBy = new HashMap<>();
	private AtomicInteger p = new AtomicInteger(0);
	
	
	public Condition(StringBuffer hql, Session session) {
		this.hql = hql;
		this.session = session;
	}
	
	/**
	 * 起始方法，默认为=
	 * @param key
	 * @param value
	 * @return
	 */
	public Middle start(String key, Object value){
		return start(key, Operation.EQ, value);
	}
	
	/**
	 * 起始方法
	 * @param key
	 * @param operation
	 * @param value
	 * @return
	 */
	public Middle start(String key, Operation operation, Object value){
		String random = "p"+p.incrementAndGet();
		if(operation == Operation.EQ && value == null){
			hql.append(" where e." + key + " is null");
		}else if(operation == Operation.NEQ && value == null){
			hql.append(" where e." + key + " is not null");
		}else if(operation == Operation.IN || operation == Operation.NIN){
			hql.append(" where e." + key + operation.getKeyword() + "(:" +random+")");
		}else{
			hql.append(" where e." + key + operation.getKeyword() + ":" + random);
		}
		if(value!=null){
			param.put(random, value);
		}
		return middle;
	}
	
	public Order order(){
		return order;
	}
	
	public Result end(){
		return result;
	}
	
	public class Middle {
		
		/**
		 * AND 默认为=
		 * @param key
		 * @param value
		 * @return
		 */
		public Middle and(String key, Object value){
			return and(key, Operation.EQ, value);
		}
		
		/**
		 * AND
		 * @param key
		 * @param operation
		 * @param value
		 * @return
		 */
		public Middle and(String key, Operation operation, Object value){
			String random = "p"+p.incrementAndGet();
			if(operation == Operation.EQ && value == null){
				hql.append(" and e." + key + " is null");
			}else if(operation == Operation.NEQ && value == null){
				hql.append(" and e." + key + " is not null");
			}else if(operation == Operation.IN || operation == Operation.NIN){
				hql.append(" and e." + key + operation.getKeyword() + "(:" +random+")");
			}else{
				hql.append(" and e." + key + operation.getKeyword() + ":" + random);
			}
			if(value!=null){
				param.put(random, value);
			}
			return this;
		}
		
		/**
		 * OR 默认为=
		 * @param key
		 * @param value
		 * @return
		 */
		public Middle or(String key, Object value){
			return or(key, Operation.EQ, value);
		}
		
		/**
		 * OR
		 * @param key
		 * @param operation
		 * @param value
		 * @return
		 */
		public Middle or(String key, Operation operation, Object value){
			String random = "p"+p.incrementAndGet();
			if(operation == Operation.EQ && value == null){
				hql.append(" or e." + key + " is null");
			}else if(operation == Operation.NEQ && value == null){
				hql.append(" or e." + key + " is not null");
			}else if(operation == Operation.IN || operation == Operation.NIN){
				hql.append(" or e." + key + operation.getKeyword() + "(:" +random+")");
			}else{
				hql.append(" or e." + key + operation.getKeyword() + ":" + random);
			}
			if(value!=null){
				param.put(random, value);
			}
			return this;
		}
		
		public Order order(){
			return order;
		}
		
		public Result end(){
			return result;
		}
	}
	
	public class Order {
		
		public Order asc(String key){
			orderBy.put(key, "ASC");
			return this;
		}
		
		public Order desc(String key){
			orderBy.put(key, "DESC");
			return this;
		}
		
		public Order on(String key, String type){
			orderBy.put(key, type);
			return this;
		}
		
		public Result end(){
			return result;
		}
		
	}
	
	public class Result {
		
		private Query common(){
			
			if(!CollectionUtils.isEmpty(orderBy)){
				hql.append(" order by ");
				boolean hasFirst = true;
				for (Entry<String, String> entry : orderBy.entrySet()) {
					if(hasFirst){
						hql.append(entry.getKey()+" "+entry.getValue());
						hasFirst = false;
					}else{
						hql.append(", "+entry.getKey()+" "+entry.getValue());
					}
				}
			}
			
			Query query = session.createQuery(hql.toString());
			for (Entry<String,Object> entry : param.entrySet()) {
				Object value = entry.getValue();
				if(ObjectUtils.isArray(value) || value instanceof Collection){
					query.setParameterList(entry.getKey(), (Object[])value);
				}else{
					query.setParameter(entry.getKey(), value);
				}
				
			}
			return query;
		}
		
		@SuppressWarnings("unchecked")
		public T unique(){
			Query query = common();
			return (T) query.uniqueResult();
		}
		
		@SuppressWarnings("unchecked")
		public List<T> list(){
			Query query = common();
			return query.list();
		}
		
		@SuppressWarnings("unchecked")
		public List<T> list(int size){
			Query query = common().setFirstResult(0).setMaxResults(size);
			return query.list();
		}
	}

}
